using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 消息监听相关
    /// </summary>
    public partial class LevelPlayEntityCtrl
    {

        protected virtual void AddMsgListener()
        {
            MsgDispatcher.AddListener<List<LevelEntityPOD>, List<int>, bool>(MsgEventType.Level_UpdateEntities, RecvUpdateEntities);
            MsgDispatcher.AddListener<LevelMoveReason, int, LevelEntityType, float, float, float, float, EntityMoveDirType>(MsgEventType.Level_SyncEntityPos, RecvSyncEntityPos);
            //MsgDispatcher.AddListener<List<int>, bool, int, bool, int>(MsgEventType.Level_EntityActive, RecvEntityActivation);
            MsgDispatcher.AddListener<int, int, bool, bool>(MsgEventType.Level_ElevatorMoveOrStop, RecvElevatorMoveOrStop);
            MsgDispatcher.AddListener<List<int>, bool>(MsgEventType.Level_NotifyEntityObstacleChange, RecvEntityObstacleChange);
            MsgDispatcher.AddListener<int, LevelEntityType, int>(MsgEventType.Level_UpdateEntityRotationY, RecvUpdateEntityRotationY);
            MsgDispatcher.AddListener<int, bool>(MsgEventType.Level_NotifyActiveCheckPoint, NotifyActiveCheckPoint);
            MsgDispatcher.AddListener<List<LevelBuffChangePOD>>(MsgEventType.Level_NotifyBuffChange, NotifyBuffChange);
            MsgDispatcher.AddListener<int, int, bool>(MsgEventType.Level_UpdateCarrier, OnCarrierChanged);
            MsgDispatcher.AddListener<int, LevelHeroPOD>(MsgEventType.Level_LeaderChanged, NotifyLeaderChanged);
            MsgDispatcher.AddListener(MsgEventType.QuestAdd, NotifyQuestAdd);
            MsgDispatcher.AddListener(MsgEventType.QuestRemove, NotifyQuestRemove);
            MsgDispatcher.AddListener<int>(MsgEventType.QuestStartTrack, NotifyQuestStartTrack);
            MsgDispatcher.AddListener<long, int, int, AttrChangeReason>(MsgEventType.Level_LeaderHeroAddHpSp, NotifyLeaderHeroAddHpSp);
            MsgDispatcher.AddListener<int, int>(MsgEventType.Level_ChangeEntityAudio, OnNotifyChangeEntityAudio);
        }

        protected virtual void RemoveMsgListener()
        {
            MsgDispatcher.RemoveListener<List<LevelEntityPOD>, List<int>, bool>(MsgEventType.Level_UpdateEntities, RecvUpdateEntities);
            MsgDispatcher.RemoveListener<LevelMoveReason, int, LevelEntityType, float, float, float, float, EntityMoveDirType>(MsgEventType.Level_SyncEntityPos, RecvSyncEntityPos);
            //MsgDispatcher.RemoveListener<List<int>, bool, int, bool, int>(MsgEventType.Level_EntityActive, RecvEntityActivation);
            MsgDispatcher.RemoveListener<int, int, bool, bool>(MsgEventType.Level_ElevatorMoveOrStop, RecvElevatorMoveOrStop);
            MsgDispatcher.RemoveListener<List<int>, bool>(MsgEventType.Level_NotifyEntityObstacleChange, RecvEntityObstacleChange);
            MsgDispatcher.RemoveListener<int, LevelEntityType, int>(MsgEventType.Level_UpdateEntityRotationY, RecvUpdateEntityRotationY);
            MsgDispatcher.RemoveListener<int, bool>(MsgEventType.Level_NotifyActiveCheckPoint, NotifyActiveCheckPoint);
            MsgDispatcher.RemoveListener<List<LevelBuffChangePOD>>(MsgEventType.Level_NotifyBuffChange, NotifyBuffChange);
            MsgDispatcher.RemoveListener<int, int, bool>(MsgEventType.Level_UpdateCarrier, OnCarrierChanged);
            MsgDispatcher.RemoveListener<int, LevelHeroPOD>(MsgEventType.Level_LeaderChanged, NotifyLeaderChanged);
            MsgDispatcher.RemoveListener(MsgEventType.QuestAdd, NotifyQuestAdd);
            MsgDispatcher.RemoveListener(MsgEventType.QuestRemove, NotifyQuestRemove);
            MsgDispatcher.RemoveListener<int>(MsgEventType.QuestStartTrack, NotifyQuestStartTrack);
            MsgDispatcher.RemoveListener<long, int, int, AttrChangeReason>(MsgEventType.Level_LeaderHeroAddHpSp, NotifyLeaderHeroAddHpSp);
            MsgDispatcher.RemoveListener<int, int>(MsgEventType.Level_ChangeEntityAudio, OnNotifyChangeEntityAudio);
        }

        private void NotifyQuestAdd()
        {
            foreach (var entity in entitys.Values)
            {
                entity.RefreshQuestState();
            }
        }

        private void NotifyQuestRemove()
        {
            foreach (var entity in entitys.Values)
            {
                entity.RefreshQuestState();
            }
        }

        private void NotifyQuestStartTrack(int cid)
        {
            GameScenePlayUtil.ShowEntityTrack().Forget();
        }

        public void RecvSyncEntityPos(LevelMoveReason reason, int entityId, LevelEntityType entityType, float x, float y, float z, float speedRatio, EntityMoveDirType dirType)
        {
            //跳跃失败需要切换状态机
            if (reason == LevelMoveReason.JumpFail)
            {
                if (regionCtrl.interactCtrl.fsm.currentStateId == LevelInteractState.Jump)
                {
                    regionCtrl.interactCtrl.fsm.ChangeState(LevelInteractState.Operational);
                }
                if (heroEntities.TryGetValue(entityId, out var entity))
                {
                    entity.SyncEntityPos(x, y, z, speedRatio, dirType, reason);
                }
            }
            //同步英雄和实体
            if (entityType == LevelEntityType.Hero)
            {
                if (heroEntities.TryGetValue(entityId, out var entity))
                {
                    entity.SyncEntityPos(x, y, z, speedRatio, dirType, reason);
                }
            }
            else
            {
                if (entitys.TryGetValue(entityId, out var entity))
                {
                    //存在就刷新
                    entity.SyncEntityPos(x, y, z, speedRatio, dirType, reason);

                    OnEntityRefreshPosOrRot(entity);
                }
            }
        }

        public void RecvUpdateEntities(List<LevelEntityPOD> modifiedList, List<int> removedList, bool isPlayDieWhenRemove)
        {
            var levelRegion = regionCtrl.levelRegion;
            if (removedList != null)
            {
                //删除实体
                foreach (var id in removedList)
                {
                    var dynEntity = RemoveEntity(id, isPlayDieWhenRemove);
                    dynEntity?.Dispose();
                }
            }

            //添加新实体，注意在回收前不要return，或return前先回收modifiedList
            if (modifiedList != null)
            {
                foreach (var pod in modifiedList)
                {
                    if (pod.IsHero())
                    {
                        //如果有
                        DynLevelHeroEntity dynEntity = null;
                        if (heroEntities.TryGetValue(pod.id, out var heroEntity))
                        {
                            dynEntity = heroEntity.dynEntity;
                            levelRegion.UpdateDynHeroEntity(pod);
                            // 刷新位置，旋转
                            var moveComponent = heroEntity.GetMoveComponent();
                            if (moveComponent != null)
                            {
                                moveComponent.SyncPositionAndRotation(dynEntity.x, dynEntity.y, dynEntity.z, GameMathUtil.IntEulerToVector3(dynEntity.dirEuler));
                            }
                            continue;
                        }
                        //如果没有
                        dynEntity = levelRegion.UpdateDynHeroEntity(pod);
                        heroEntity = LevelEntityFactory.CreateEntity(dynEntity);
                        heroEntities.Add(pod.id, heroEntity);

                        UniTask.Void(async () =>
                        {
                            await heroEntity.LoadAndInstantiate(entityHolder);
                            OnHeroEntityCreate(heroEntity);
                        });
                    }
                    else
                    {
                        if (entitys.TryGetValue(pod.id, out var entity))
                        {
                            // 实体已存在，全量刷新
                            var dynEntity = entity.GetDynLevelEntity();
                            var oldIsObstacleActive = dynEntity.isObstacleActive;
                            var oldActive = dynEntity.active;
                            // 刷新数据
                            levelRegion.UpdateDynEntity(pod, out bool isPos2DChanged, out bool isPosYChanged);
                            if (isPos2DChanged)
                            {
                                OnEntityRefreshPosOrRot(entity);
                            }
                            if (isPosYChanged)
                            {
                                if (dynEntity.levelEntityConfig.paramMap.ContainsKey(EntityDynamicParamType.Elevator))
                                {
                                    entity.GetElevatorComponent().OnServiceRefreshY();
                                }
                            }

                            // 刷新实体的障碍物状态
                            if (dynEntity.isObstacleActive != oldIsObstacleActive)
                            {
                                RefreshEntityObstacle(entity, dynEntity, dynEntity.isObstacleActive);
                            }

                            // 刷新激活状态
                            if (oldActive != dynEntity.active)
                            {
                                SetEntityActivation(entity, dynEntity.active);
                            }

                            // 刷新位置，旋转
                            var moveComponent = entity.GetMoveComponent();
                            if (moveComponent != null)
                            {
                                moveComponent.SyncPositionAndRotation(dynEntity.x, dynEntity.y, dynEntity.z, GameMathUtil.IntEulerToVector3(dynEntity.dirEuler));
                            }

                            continue;
                        }
                        // 以下为创建新的实体
                        var newDynEntity = levelRegion.UpdateDynEntity(pod, out _, out _);
                        if (newDynEntity == null)
                        {
                            continue;
                        }
                        AddEntityByDynData(newDynEntity).Forget();
                    }
                }
            }
        }

        /// <summary>
        /// 同步电梯移动或停止
        /// </summary>
        /// <param name="elevatorEntityId"></param>
        /// <param name="targetFloor"></param>
        /// <param name="isRidingMode">是否乘坐模式（否则是召唤模式）</param>
        /// <param name="isMoveState">是否启动（否则是停止）</param>
        public void RecvElevatorMoveOrStop(int elevatorEntityId, int targetFloor, bool isRidingMode, bool isMoveState)
        {
            if (!entitys.TryGetValue(elevatorEntityId, out var entity))
            {
                LogGame.LogError("[LevelPlayEntityCtrl|RecvSyncElevatorFloor]Can't found Entity,id:" + elevatorEntityId);
                return;
            }
            if (isMoveState)
            {
                var elevator = entity.GetLevelElevatorComponent();
                if (elevator != null)
                {
                    elevator.SetTargetFloor(targetFloor);
                }
                else
                {
                    LogGame.LogError("[LevelPlayEntityCtrl|RecvSyncElevatorFloor] Can't found Elevator,id:" + elevatorEntityId);
                }
            }
            entity.GetElevatorComponent()?.OnMoveStateChange(!isMoveState);
        }

        private void RefreshEntityObstacle(LevelPlayBaseEntity entity, DynLevelEntity dynEntity, bool isObstacleActive)
        {
            dynEntity.UpdateObstacleActive(isObstacleActive);
            var moveComponent = entity.GetMoveComponent();
            moveComponent?.SetColliderActive(isObstacleActive);
            if (dynEntity.activateWallActionPlay)
            {
                // 尝试播放阻挡修改动画
                var animationComponent = entity.GetAnimationComponent();
                if (animationComponent != null)
                {
                    animationComponent.PlayStateOpenClose(!isObstacleActive);
                }
            }
        }

        public void RecvEntityObstacleChange(List<int> entityIdList, bool isObstacleActive)
        {
            foreach (int entityId in entityIdList)
            {
                if (!entitys.TryGetValue(entityId, out var entity))
                {
                    LogGame.LogError("[LevelPlayEntityCtrl|RecvEntityObstacleChange] Can't found Entity,id:" + entityId);
                    return;
                }
                var dynEntity = entity.GetDynLevelEntity();
                if (dynEntity == null)
                {
                    continue;
                }
                if (dynEntity.isObstacleActive == isObstacleActive)
                {
                    continue;
                }
                RefreshEntityObstacle(entity, dynEntity, isObstacleActive);
            }
        }

        public void RecvUpdateEntityRotationY(int entityId, LevelEntityType entityType, int rotationY)
        {
            switch (entityType)
            {
                case LevelEntityType.Normal:
                    if (!entitys.TryGetValue(entityId, out var entity))
                    {
                        LogGame.LogError("[LevelPlayEntityCtrl|RecvUpdateEntityRotationY] Can't found Entity,id:" + entityId);
                        return;
                    }
                    var moveComponent = entity.GetMoveComponent();
                    moveComponent?.RotateAfterMove(rotationY);
                    break;
                case LevelEntityType.Hero:
                    var mainCharacter = GetMainCharacter();
                    var mainMoveComponent = mainCharacter.GetMoveComponent();
                    mainMoveComponent?.RotateAfterMove(rotationY);
                    break;
            }
        }


        public void NotifyActiveCheckPoint(int entityId, bool isActive)
        {
            if (!entitys.TryGetValue(entityId, out var entity))
            {
                LogGame.LogError("[LevelPlayEntityCtrl|NotifyActiveCheckPoint] Can't found Entity,id:" + entityId);
                return;
            }
            var dynEntity = entity.GetDynLevelEntity();
            if (dynEntity != null)
            {
                // TODO 做相应的表现
                dynEntity.UpdateCheckPointActive(isActive);
            }
        }

        public void NotifyBuffChange(List<LevelBuffChangePOD> changes)
        {
            for (int i = 0; i < changes.Count; i++)
            {
                var changePod = changes[i];
                switch ((LevelBuffHostType)changePod.hostType)
                {
                    case LevelBuffHostType.Player:
                        levelPlayCtrl.levelPlayer.buffHolder.ProcessBuffChange(changePod);
                        break;
                    case LevelBuffHostType.SingleHero:

                        break;
                    case LevelBuffHostType.Entity:
                        if (!entitys.TryGetValue(((int)changePod.hostId), out var entity))
                        {
                            break;
                        }
                        var dynEntity = entity.GetDynLevelEntity();
                        if (dynEntity != null)
                        {
                            dynEntity.buffHolder.ProcessBuffChange(changePod);
                        }
                        break;
                    default:
                        LogGame.LogWarning("[LevelPlayEntityCtrl|NotifyBuffChange] Unknow hostType:" + changePod.hostType);
                        break;
                }

            }
        }

        private void OnCarrierChanged(int heroEntityId, int carrierEntityId, bool isRemoved)
        {
            if (heroEntities.TryGetValue(heroEntityId, out var characterEntity))
            {
                characterEntity.GetMoveComponent().ChangeCarrier(carrierEntityId, isRemoved);
            }
        }

        private void NotifyLeaderChanged(int heroEntityId, LevelHeroPOD leaderHeroPOD)
        {
            var levelPlay = LevelPlayModule.Instance.levelPlay;
            levelPlay.levelPlayer.leaderHeroId = leaderHeroPOD.id;
            if (heroEntities.TryGetValue(heroEntityId, out var characterEntity))
            {
                characterEntity.ChangeHero(leaderHeroPOD).Forget();
            }
        }

        private void NotifyLeaderHeroAddHpSp(long leaderHeroId, int addHp, int addSp, AttrChangeReason reason)
        {
            if (addHp != 0 && _characterEntity.dynLevelHero.id == leaderHeroId)
            {
                var bindCom = _characterEntity.GetComponent<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
                var topBp = bindCom.GetBindPoint(EntityBindPointCommonType.Top);
                var numType = addHp > 0 ? EHUDNumberRenderType.Cure : EHUDNumberRenderType.NormalHurt;
                HUDNumberRender.Instance.AddHudNumber(topBp.position, Vector3.zero, (int)numType, Math.Abs(addHp));
            }
            if (reason == AttrChangeReason.UnderAttack)
            {
                LevelCharacterEntity targetHeroEntity = null;
                foreach (var kv in heroEntities)
                {
                    if (kv.Value.dynLevelHero.id == leaderHeroId)
                    {
                        targetHeroEntity = kv.Value;
                        break;
                    }
                }
                targetHeroEntity?.GetAnimationComponent()?.PlayHit();
            }
        }

        private void OnNotifyChangeEntityAudio(int entityId, int audioCid)
        {
            if (!entitys.TryGetValue(entityId, out var entity))
            {
                LogGame.LogError("[LevelPlayEntityCtrl|OnNotifyChangeEntityAudio] Can't found Entity,id:" + entityId);
                return;
            }
            entity.GetDynLevelEntity().loopAudio = audioCid;
            entity.GetAudioComponent().PlayAudio(audioCid);
        }
    }
}
